import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_windowmanager/flutter_windowmanager.dart';
import 'package:lib_database/objectbox.dart';
import 'package:lib_util/utils/utils.dart';
import 'package:local_auth/local_auth.dart';
import 'package:lib_database/src/config.dart';
import 'package:lib_language/lib_language.dart';
import 'package:provider/provider.dart';
import 'package:lib_database/src/model/user_settings_model/user_settings_model.dart';
import '../bridge/native_channel_bridge.dart';
import '../provider/nav_key.dart';
import '../widgets/dialog/password_auth_dialog.dart';
import 'package:aichat_flutter_wallet/module_common/provider/user_settings_provider.dart';
import 'package:aichat_flutter_wallet/module_common/widgets/public_tip/public_tip.dart';

class Authentication {
  Authentication._privateConstructor();

  static final Authentication _instance = Authentication._privateConstructor();

  factory Authentication() {
    return _instance;
  }

  Future<bool> canCheckBiometric({LocalAuthentication? auth}) async {
    auth ??= LocalAuthentication();
    bool support = await auth.canCheckBiometrics;
    if (!support) return false;
    List<BiometricType> list = await auth.getAvailableBiometrics();
    return list.isNotEmpty;
  }

  Future<bool> startBiometricOnlyAuth() {
    LocalAuthentication auth = LocalAuthentication();
    return auth.authenticate(
        localizedReason: LocaleKeys.yanzheng.tr(),
        options: const AuthenticationOptions(biometricOnly: true));
  }

  Future<bool> startLocalAuth(
      {bool showPasswordError = true, Function? callBackError,String title=''}) async {
    UserSettings settings = ObjectBox()
        .userSettingsModel
        .getUserSettingsByUId(NativeChannelBridge.instance.appCommMsg!.userId);
    if (settings.biometrics) {
      //使用生物特征支付
      LocalAuthentication auth = LocalAuthentication();
      bool support = await canCheckBiometric(auth: auth);
      //不支持生物特征，直接去验证密码
      if (!support) {
        return _startPasswordAuth(
            showPasswordError: showPasswordError,
            callBackError: callBackError,title: title);
      }
      try {
        final bool didAuthenticate = await auth.authenticate(
            localizedReason: LocaleKeys.yanzheng.tr(),
            options: const AuthenticationOptions(biometricOnly: true));
        Config.logger.d('didAuthenticate:$didAuthenticate');
        if (didAuthenticate) {
          return true;
        } else {
          return _startPasswordAuth(
              showPasswordError: showPasswordError,
              callBackError: callBackError);
        }
      } catch (e) {
        Config.logger.e(e);
        //使用密码支付
        return _startPasswordAuth(
            showPasswordError: showPasswordError,
            callBackError: callBackError,title: title);
      }
    } else {
      //使用密码支付
      return _startPasswordAuth(
          showPasswordError: showPasswordError, callBackError: callBackError);
    }
  }

  Future<bool> _startPasswordAuth(
      {bool emptyGoSet = true,
      bool showPasswordError = true,
        Function? callBackError,String title=''}) async {
    UserSettings settings = ObjectBox()
        .userSettingsModel
        .getUserSettingsByUId(NativeChannelBridge.instance.appCommMsg!.userId);
    if (Utils.isEmpty(settings.password)) {
      if (emptyGoSet) {
        return setPassword(title:title);
      } else {
        return false;
      }
    }

    if (Platform.isAndroid) {
      await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
    }
    dynamic result = await Utils.showBottomSheetDialog(
        NavKey.navKey.currentContext!, const PasswordAuthDialog());
    if (Platform.isAndroid) {
      //延迟1s解除安全屏幕,密码框消失有一定延迟
      Future.delayed(const Duration(seconds: 1)).then((value) {
        FlutterWindowManager.clearFlags(FlutterWindowManager.FLAG_SECURE);
      });
    }

    if (null != result && result is String && Utils.isNotEmpty(result)) {
      if (_encryptPassword(result) == settings.password) {
        return true;
      } else {
        if(callBackError!=null)callBackError();
        if (showPasswordError) {
          Toast.show( NavKey.navKey.currentContext as BuildContext,
              status: '1',
              message: LocaleKeys.mimacuowu.tr(),
              duration: Duration(milliseconds: 3000));
        }
      }
    }

    return false;
  }

  Future<bool> setPassword({String title='Please set wallet password'}) async {
    UserSettingsProvider provider =
        NavKey.navKey.currentContext!.read<UserSettingsProvider>();

    dynamic result1 =
        await _goSetPassword(title);
    if (null != result1 && result1 is String && Utils.isNotEmpty(result1)) {
      dynamic result2 =
          await _goSetPassword(title);
      if (null != result2 && result2 is String && Utils.isNotEmpty(result2)) {
        if (result1 == result2) {
          // String password = _encryptPassword(result1);
          // provider.updateSettings(password: password);
          updateObPassword(result1, provider);

          Toast.show(NavKey.navKey.currentContext as BuildContext,
              message: LocaleKeys.mimashezhichenggong.tr(),
              duration: Duration(milliseconds: 2000));
          return true;
        } else {
          Toast.show(NavKey.navKey.currentContext as BuildContext,
              status: '2',
              message: LocaleKeys.liangcimimashurubuyizhi.tr(),
              duration: Duration(milliseconds: 2000));
          return false;
        }
      }
    }
    return false;
  }

  Future<bool> changePassword() async {
    bool result = await _startPasswordAuth(emptyGoSet: false);
    if (result) {
      return setPassword();
    }
    return false;
  }

  _goSetPassword(String title) {
    return Utils.showBottomSheetDialog(
        NavKey.navKey.currentContext!,
        PasswordAuthDialog(
          title: title,
        ));
  }

  void updateObPassword(String pwd, UserSettingsProvider provider,
      {bool? biometric = null}) {
    String password = _encryptPassword(pwd);
    provider.updateSettings(password: password, biometric: biometric);
  }

  bool validPassword(String pwd) {
    String? password = ObjectBox().userSettingsModel.getUserSettings().password;
    return Utils.isNotEmpty(password) && _encryptPassword(pwd) == password;
  }

  String _encryptPassword(String password) {
    return md5.convert(md5.convert(password.codeUnits).bytes).toString();
  }
}
